package com.huaboot.generator.service;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huaboot.commont.exception.BusinessException;
import com.huaboot.commont.exception.ErrorCode;
import com.huaboot.commont.page.PageResult;
import com.huaboot.commont.utils.DateUtils;
import com.huaboot.generator.config.GenConfig;
import com.huaboot.generator.config.template.TemplateInfo;
import com.huaboot.generator.entity.FieldTypeEntity;
import com.huaboot.generator.entity.TableEntity;
import com.huaboot.generator.entity.TableFieldEntity;
import com.huaboot.generator.enums.AutoFillEnum;
import com.huaboot.generator.enums.FormLayoutEnum;
import com.huaboot.generator.enums.GeneratorTypeEnum;
import com.huaboot.generator.mapper.GeneratorMapper;
import com.huaboot.generator.mapper.TableMapper;
import com.huaboot.generator.query.GeneratorQuery;
import com.huaboot.generator.utils.GenUtils;
import com.huaboot.generator.utils.TemplateInfoUtils;
import com.huaboot.generator.utils.TemplateUtils;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * description: DataSourceServiceImpl
 * date: 2023/8/11 16:03
 * author: ff
 */
@Service
public class GeneratorServiceImpl implements GeneratorService {

    @Autowired
    private GeneratorMapper generatorMapper;

    @Autowired
    private TableMapper tableMapper;

    @Autowired
    private TableFieldService tableFieldService;

    @Autowired
    private FieldTypeService fieldTypeService;

    @Autowired
    private  GenConfig genConfig;

    @Override
    public PageResult<TableEntity> getAllTableList(GeneratorQuery generatorQuery) {
        PageHelper.startPage(generatorQuery.currentPage, generatorQuery.size);
        LambdaQueryWrapper<TableEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight( StrUtil.isNotBlank(generatorQuery.getTableName()),TableEntity::getTableName, generatorQuery.getTableName());
        List<TableEntity> tableEntities = tableMapper.selectList(queryWrapper);
        PageInfo<TableEntity> page = new PageInfo<>(tableEntities);
        return new PageResult<>(page.getList(), page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncTable(Long id) {
        TableEntity tableEntity = tableMapper.selectById(id);
        if (tableEntity == null){
            throw new BusinessException(ErrorCode.GENERATOR_ERROR,"同步失败，请检查数据库表");
        }
        // 查询最新表字段列表
        List<TableFieldEntity> dbTableFieldList = generatorMapper.getTableFieldByTableName(tableEntity.getTableName());
        if (dbTableFieldList.size() == 0) {
            throw new BusinessException(ErrorCode.GENERATOR_ERROR,"同步失败，请检查数据库表：" + tableEntity.getTableName());
        }
        List<String> dbTableFieldNameList = dbTableFieldList.stream().map(TableFieldEntity::getFieldName).collect(Collectors.toList());


        //数据库中取出之前存贮的表字段
        List<TableFieldEntity> tableFieldEntityList = tableFieldService.getTableFieldListByTableId(tableEntity.getId());
        Map<String, TableFieldEntity> tableFieldMap = tableFieldEntityList.stream().collect(Collectors.toMap(TableFieldEntity::getFieldName, Function.identity()));

        //初始化表结构增加数据库字段和表字段的映射关系
        initFieldList(dbTableFieldList);

        // 同步表结构字段
        dbTableFieldList.forEach(field -> {
            // 新增字段
            if (!tableFieldMap.containsKey(field.getFieldName())) {
                field.setTableId(id);
                tableFieldService.save(field);
                return;
            }

            // 修改字段
            TableFieldEntity updateField = tableFieldMap.get(field.getFieldName());
            updateField.setPrimaryPk(field.isPrimaryPk());
            updateField.setFieldComment(field.getFieldComment());
            updateField.setFieldType(field.getFieldType());
            updateField.setAttrType(field.getAttrType());

            tableFieldService.updateById(updateField);
        });

        // 删除数据库表中没有的字段
        List<TableFieldEntity> delFieldList = tableFieldEntityList.stream().filter(field -> !dbTableFieldNameList.contains(field.getFieldName())).collect(Collectors.toList());
        if (delFieldList.size() > 0) {
            List<Long> fieldIds = delFieldList.stream().map(TableFieldEntity::getId).collect(Collectors.toList());
            tableFieldService.removeBatchByIds(fieldIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void tableImport(List<String> tableNameList) {
        for (String tableName : tableNameList) {
            //验证导入的表是否已经导入过
            LambdaQueryWrapper<TableEntity> queryWrapper = Wrappers.lambdaQuery();
            TableEntity tableEntity = tableMapper.selectOne(queryWrapper.eq(TableEntity::getTableName, tableName));
            if (tableEntity!=null){
                throw new BusinessException(ErrorCode.GENERATOR_ERROR,tableName + "已存在");
            }

            //没导入过、查询库中表的结构信息
            GeneratorQuery generatorQuery = new GeneratorQuery();
            generatorQuery.setTableName(tableName);
            TableEntity tableByTable = generatorMapper.getTableByTableName(generatorQuery);

            //把导入的这个表信息插入到表中
            // 代码生成器信息

            // 保存表信息
            tableByTable.setEmail(genConfig.getEmail());
            tableByTable.setPackageName(genConfig.getPackageName());
            tableByTable.setVersion(genConfig.getVersion());
            tableByTable.setBackendPath(genConfig.getBackendPath());
            tableByTable.setFrontendPath(genConfig.getFrontendPath());
            tableByTable.setAuthor(genConfig.getAuthor());
            tableByTable.setFormLayout(FormLayoutEnum.ONE.getValue());
            tableByTable.setGeneratorType(GeneratorTypeEnum.ZIP_DOWNLOAD.ordinal());
            tableByTable.setClassName(NamingCase.toPascalCase(tableName));
            tableByTable.setModuleName(GenUtils.getModuleName(genConfig.getPackageName()));
            tableByTable.setFunctionName(GenUtils.getFunctionName(tableName));
            tableByTable.setCreateTime(new Date());
            tableMapper.insert(tableByTable);

            //将表中的字段信息插入到表字段信息表中
            // 获取原生字段数据
            List<TableFieldEntity> tableFieldList = generatorMapper.getTableFieldByTableName(tableByTable.getTableName());
            // 初始化字段数据
            initFieldList(tableFieldList);
            // 保存列数据
            for (TableFieldEntity tableFieldEntity : tableFieldList) {
                tableFieldEntity.setTableId(tableByTable.getId());
                tableFieldService.save(tableFieldEntity);
            }

        }
    }

    /**
     * 代码生成
     * 把表中字段条件拿出来封装成map
     * 调用模板，画上去
     * 下载模板
     * @param tableNameList
     */
    @Override
    public byte[] codeDownload(String tableNameList) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        TemplateInfoUtils templateInfoUtils = new TemplateInfoUtils();
        // 生成代码
        for (String tableIdStr : tableNameList.split(",")) {
            long tableId = Long.parseLong(tableIdStr);
            // 封装模板所需要的数据模型 k-v
            Map<String, Object> dataModel = getDataModel(tableId);
            for (TemplateInfo template : templateInfoUtils.getGeneratorConfig(TemplateInfoUtils.templateInfoList)) {
                dataModel.put("templateName", template.getTemplateName());
                String content = TemplateUtils.getContent(template.getTemplateContent(), dataModel);
                String path = TemplateUtils.getContent(template.getGeneratorPath(), dataModel);
                String result = trimStringBefore(path, "hua-boot");

                try {
                    // 添加到zip
                    zip.putNextEntry(new ZipEntry(result));
                    IoUtil.writeUtf8(zip, false, content);
                    zip.flush();
                    zip.closeEntry();
                } catch (IOException e) {
                    throw new BusinessException(ErrorCode.GENERATOR_ERROR,"模板写入失败：" + path+e.getMessage());
                }
            }
        }

        return outputStream.toByteArray();
    }

    /**
     * 获取数据所有表
     * @return
     */
    @Override
    public List<TableEntity> getTableList() {
        return generatorMapper.getAllTableList();
    }

    private Map<String, Object> getDataModel(Long tableId) {
        //获取表信息+表中字段信息
        TableEntity table = tableMapper.selectById(tableId);
        List<TableFieldEntity> fieldList = tableFieldService.getTableFieldListByTableId(table.getId());
        table.setFieldList(fieldList);
        //获取模板列表
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("dbType", "MySQL");
        //遍历模板，填充内容
        // 项目信息
        dataModel.put("package", table.getPackageName().replaceFirst("\\.[^.]*$", ""));
        dataModel.put("packagePath", table.getPackageName().replace(".", File.separator));
        dataModel.put("version", table.getVersion());
        dataModel.put("moduleName", table.getModuleName());
        dataModel.put("ModuleName", StrUtil.upperFirst(table.getModuleName()));
        dataModel.put("functionName", table.getFunctionName());
        dataModel.put("FunctionName", StrUtil.upperFirst(table.getFunctionName()));
        dataModel.put("formLayout", table.getFormLayout());

        // 开发者信息
        dataModel.put("author", table.getAuthor());
        dataModel.put("email", table.getEmail());
        dataModel.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        dataModel.put("date", DateUtils.format(new Date(), DateUtils.DATE_PATTERN));

        // 设置字段分类
        setFieldTypeList(dataModel, table);

        // 设置基类信息
      //  setBaseClass(dataModel, table);

        // 导入的包列表
        Set<String> importList = fieldTypeService.getPackageByTableId(table.getId());
        dataModel.put("importList", importList);

        // 表信息
        dataModel.put("tableName", table.getTableName());
        dataModel.put("tableComment", table.getTableComment());
        dataModel.put("className", StrUtil.lowerFirst(table.getClassName()));
        dataModel.put("ClassName", table.getClassName());
        dataModel.put("fieldList", table.getFieldList());

        // 生成路径
        dataModel.put("backendPath", table.getBackendPath());
        dataModel.put("frontendPath", table.getFrontendPath());

        return dataModel;
    }

    public void initFieldList(List<TableFieldEntity> tableFieldList) {
        // 字段类型、属性类型映射
        Map<String, FieldTypeEntity> fieldTypeMap = fieldTypeService.getMap();
        int index = 0;
        for (TableFieldEntity field : tableFieldList) {
            field.setAttrName(StringUtils.underlineToCamel(field.getFieldName()));
            // 获取字段对应的类型
            FieldTypeEntity fieldTypeMapping = fieldTypeMap.get(field.getFieldType().toLowerCase());
            if (fieldTypeMapping == null) {
                // 没找到对应的类型，则为Object类型
                field.setAttrType("Object");
            } else {
                field.setAttrType(fieldTypeMapping.getAttrType());
                field.setPackageName(fieldTypeMapping.getPackageName());
            }

            field.setAutoFill(AutoFillEnum.DEFAULT.name());
            field.setFormItem(true);
            field.setGridItem(true);
            field.setQueryType("=");
            field.setQueryFormType("text");
            field.setFormType("text");
            field.setSort(index++);
        }
    }

    /**
     * 设置字段分类信息
     *
     * @param dataModel 数据模型
     * @param table     表
     */
    private void setFieldTypeList(Map<String, Object> dataModel, TableEntity table) {
        // 主键列表 (支持多主键)
        List<TableFieldEntity> primaryList = new ArrayList<>();
        // 表单列表
        List<TableFieldEntity> formList = new ArrayList<>();
        // 网格列表
        List<TableFieldEntity> gridList = new ArrayList<>();
        // 查询列表
        List<TableFieldEntity> queryList = new ArrayList<>();

        for (TableFieldEntity field : table.getFieldList()) {
            if (field.isPrimaryPk()) {
                primaryList.add(field);
            }
            if (field.isFormItem()) {
                formList.add(field);
            }
            if (field.isGridItem()) {
                gridList.add(field);
            }
            if (field.isQueryItem()) {
                queryList.add(field);
            }
        }
        dataModel.put("primaryList", primaryList);
        dataModel.put("formList", formList);
        dataModel.put("gridList", gridList);
        dataModel.put("queryList", queryList);
    }
    public static String trimStringBefore(String input, String target) {
        int index = input.indexOf(target);
        if (index >= 0) {
            // 截取目标字符串之后的部分
            return input.substring(index);
        } else {
            // 目标字符串不在输入字符串中，返回空字符串
            return "";
        }
    }
}
